package org.zjx.resource;

import com.alibaba.fastjson2.JSON;
import lombok.Getter;
import lombok.SneakyThrows;
import org.zjx.file.FileUtil;

import javax.crypto.SecretKey;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class ResourceManager {
    // 资源类型常量
    @Getter
    public enum ResourceType {
        ENCRYPTED(".enc"),
        PLAIN_TEXT(".json"),
        PLAIN_IMAGE(".png");

        private final String suffix;

        ResourceType(String suffix) {
            this.suffix = suffix;
        }
    }

    private final ConcurrentHashMap<String, String> resourceCache;
    private final ReentrantLock resourceLock;
    private SecretKey encryptionKey;

    public static IBaseConfig CONFIG;
    public static final String DEFAULT_KEY_STRING = "你个王八蛋";

    private ResourceManager() {
        resourceCache = new ConcurrentHashMap<>();
        resourceLock = new ReentrantLock();
        refreshEncryptionKey();
    }

    private static final class InstanceHolder {
        static final ResourceManager instance = new ResourceManager();
    }

    public static ResourceManager getInstance() {
        return InstanceHolder.instance;
    }

    /**
     * 刷新加密密钥
     */
    public void refreshEncryptionKey() {
        resourceLock.lock();
        try {
            if (CONFIG != null && CONFIG.getResSecretKey() != null) {
                encryptionKey = CONFIG.getResSecretKey();
            } else {
                encryptionKey = ResourceEncryptor.getKeyFromString(DEFAULT_KEY_STRING);
            }
        } finally {
            resourceLock.unlock();
        }
    }

    /**
     * 获取完整资源路径
     */
    public String getResourcePath(String resType, String classify, String fileName, ResourceType resourceType) {
        if (fileName == null) return null;

        // 使用Path构建路径确保跨平台兼容性
        Path path = Paths.get("");

        // 添加基础资源路径
        if (CONFIG != null && CONFIG.getResourcePath() != null) {
            path = Paths.get(CONFIG.getResourcePath());
        }

        // 添加资源类型目录
        if (resType != null && !resType.isEmpty()) {
            path = path.resolve(resType);
        }

        // 添加分类目录
        if (classify != null && !classify.isEmpty()) {
            path = path.resolve(classify);
        }

        // 添加文件名和后缀
        return path.resolve(fileName + resourceType.getSuffix()).toString();
    }

    /**
     * 保存资源（加密）
     */
    @SneakyThrows
    public void saveImageResource(BufferedImage image, String resType, String classify, String fileName) {
        String filePath = getResourcePath(resType, classify, fileName, ResourceType.PLAIN_IMAGE);
        new FileUtil().writeImage(image,"png", filePath);
        System.out.println("加密资源保存成功: " + filePath);
    }

    /**
     * 保存资源（加密）
     */
    @SneakyThrows
    public void saveResource(Object object, String resType, String classify, String fileName) {
        String filePath = getResourcePath(resType, classify, fileName, ResourceType.ENCRYPTED);
        ResourceEncryptor.encryptAndSaveToFile(object, filePath, encryptionKey);
        System.out.println("加密资源保存成功: " + filePath);
    }

    /**
     * 保存资源（明文）
     */
    @SneakyThrows
    public void saveResourceWithoutEncryption(Object object, String resType, String classify, String fileName) {
        String filePath = getResourcePath(resType, classify, fileName, ResourceType.PLAIN_TEXT);
        String json = JSON.toJSONString(object);

        json = json.replace("\"@type\":\"java.util.HashMap\",","");
        json = json.replace("\"@type\":\"java.util.HashMap\"","");

        // 确保目录存在
        Path path = Paths.get(filePath);
        Files.createDirectories(path.getParent());

        // 写入文件（兼容 Java 8）
        try (OutputStream out = Files.newOutputStream(path)) {
            out.write(json.getBytes(StandardCharsets.UTF_8));
        }
        System.out.println("明文资源保存成功: " + filePath);
    }

    /**
     * 保存资源（加密）
     */
    @SneakyThrows
    public BufferedImage loadImageResource(String resType, String classify, String fileName) {
        String filePath = getResourcePath(resType, classify, fileName, ResourceType.PLAIN_IMAGE);
        System.out.println("资源加载成功: " + filePath);
        return new FileUtil().readImage(filePath);
    }

    /**
     * 加载资源（通用方法）
     */
    public String loadResource(String resType, String classify, String fileName, ResourceType resourceType) {
        String resourcePath = getResourcePath(resType, classify, fileName, resourceType);
        String cacheKey = generateCacheKey(resType, classify, fileName, resourceType);

        resourceLock.lock();
        try {
            // 检查缓存
            if (resourceCache.containsKey(cacheKey)) {
                return resourceCache.get(cacheKey);
            }

            // 加载资源
            String resourceData;
            if (resourceType == ResourceType.ENCRYPTED) {
                resourceData = loadEncryptedResource(resourcePath);
            } else {
                resourceData = loadTextResource(resourcePath);
            }

            // 更新缓存
            resourceCache.put(cacheKey, resourceData);
            System.out.println("资源加载成功: " + resourcePath);
            return resourceData;
        } finally {
            resourceLock.unlock();
        }
    }

    /**
     * 加载加密资源
     */
    private String loadEncryptedResource(String resourcePath) {
        try (InputStream inputStream = Files.newInputStream(Paths.get(resourcePath))) {
            byte[] decryptedData = ResourceDecryptor.decryptFromStream(inputStream, encryptionKey);
            return new String(decryptedData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new ResourceLoadException("解密资源失败: " + resourcePath, e);
        }
    }

    /**
     * 加载文本资源（兼容 Java 8）
     */
    private String loadTextResource(String resourcePath) {
        try {
            return readFileAsString(Paths.get(resourcePath));
        } catch (IOException e) {
            throw new ResourceLoadException("读取资源失败: " + resourcePath, e);
        }
    }

    /**
     * 高效、健壮的文件读取方法（兼容 Java 8）
     */
    private String readFileAsString(Path path) throws IOException {
        // 检查文件是否存在
        if (!Files.exists(path)) {
            throw new FileNotFoundException("文件不存在: " + path);
        }

        // 检查是否为文件
        if (!Files.isRegularFile(path)) {
            throw new IOException("路径不是文件: " + path);
        }

        // 估计文件大小
        long fileSize = Files.size(path);
        int initialCapacity = (fileSize > 0 && fileSize < Integer.MAX_VALUE) ?
                (int) fileSize : 16384; // 16KB 默认

        try (
                InputStream inputStream = Files.newInputStream(path);
                Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8))
        {
            StringBuilder content = new StringBuilder(initialCapacity);
            char[] buffer = new char[16384]; // 16KB 缓冲区
            int charsRead;

            while ((charsRead = reader.read(buffer)) != -1) {
                content.append(buffer, 0, charsRead);
            }

            return content.toString();
        } catch (IOException e) {
            throw new IOException("读取文件失败: " + path, e);
        }
    }

    /**
     * 解析资源为对象
     */
    public <T> T parseResourceToObject(String resType, String classify, String fileName,
                                       ResourceType resourceType, Class<T> classType) {
        String resourceData = loadResource(resType, classify, fileName, resourceType);
        return parseJsonToObject(resourceData, classType);
    }

    /**
     * 解析资源为泛型对象（支持List/Map等）
     */
    public <T> T parseResourceToGenericObject(String resType, String classify, String fileName,
                                              ResourceType resourceType,  Type type) {
        String resourceData = loadResource(resType, classify, fileName, resourceType);
        return parseJsonToGenericObject(resourceData, type);
    }

    /**
     * 解析JSON为对象
     */
    private <T> T parseJsonToObject(String json, Class<T> classType) {
        if (json == null || json.isEmpty()) {
            throw new ResourceParseException("JSON内容为空");
        }
        try {
            return JSON.parseObject(json, classType);
        } catch (Exception e) {
            throw new ResourceParseException("JSON解析失败", e);
        }
    }

    /**
     * 解析JSON为泛型对象
     */
    private <T> T parseJsonToGenericObject(String json, Type type) {
        if (json == null || json.isEmpty()) {
            throw new ResourceParseException("JSON内容为空");
        }
        try {
            return JSON.parseObject(json, type);
        } catch (Exception e) {
            throw new ResourceParseException("JSON解析失败", e);
        }
    }

    /**
     * 生成缓存键
     */
    private String generateCacheKey(String resType, String classify, String fileName, ResourceType resourceType) {
        return String.format("%s:%s:%s:%s", resType, classify, fileName, resourceType.name());
    }

    /**
     * 卸载资源
     */
    public void unloadResource(String resType, String classify, String fileName, ResourceType resourceType) {
        String cacheKey = generateCacheKey(resType, classify, fileName, resourceType);
        resourceCache.remove(cacheKey);
    }

    /**
     * 清除所有缓存
     */
    public void clearAllCache() {
        resourceCache.clear();
    }

    // 自定义异常类
    public static class ResourceLoadException extends RuntimeException {
        public ResourceLoadException(String message) {
            super(message);
        }

        public ResourceLoadException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    public static class ResourceParseException extends RuntimeException {
        public ResourceParseException(String message) {
            super(message);
        }

        public ResourceParseException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}